package cn.goour.web.sys.service

import cn.goour.web.base.entity.PageInfo
import cn.goour.web.sys.entity.Admin
import cn.goour.web.sys.entity.Log
import cn.goour.web.sys.entity.User
import cn.goour.web.sys.repository.LogRepository
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.data.domain.Page
import org.springframework.data.domain.PageRequest
import org.springframework.data.domain.Sort
import org.springframework.stereotype.Service
import javax.annotation.PostConstruct
import javax.persistence.criteria.CriteriaBuilder
import javax.persistence.criteria.CriteriaQuery
import javax.persistence.criteria.Predicate
import javax.persistence.criteria.Root
import javax.transaction.Transactional

@Service
@Transactional
open class LogService {

    @Autowired private
    lateinit var logRepository: LogRepository

    open fun getList(pageInfo: PageInfo): Page<Log> {
        val pageRequest = PageRequest(pageInfo.page - 1, pageInfo.size, Sort(Sort.Order(Sort.Direction.DESC, "id")))
        return logRepository.findAll({ root: Root<Log>, criteriaQuery: CriteriaQuery<*>, criteriaBuilder: CriteriaBuilder ->
            getSearch(pageInfo.search, root, criteriaQuery, criteriaBuilder)
        }, pageRequest)
    }

    open fun getAdminLogs(pageInfo: PageInfo): Page<Log> {
        val pageRequest = PageRequest(pageInfo.page - 1, pageInfo.size, Sort(Sort.Order(Sort.Direction.DESC, "id")))
        return logRepository.findAll({ root: Root<Log>, criteriaQuery: CriteriaQuery<*>, criteriaBuilder: CriteriaBuilder ->
            if (pageInfo.search.isBlank()) {
                criteriaBuilder.equal(root.get<String>("type"), "admin")
            } else {
                val search = getSearch(pageInfo.search, root, criteriaQuery, criteriaBuilder)

                val c1 = criteriaBuilder.equal(root.get<String>("type"), "admin")

                criteriaBuilder.and(c1, search)
            }
        }, pageRequest)
    }

    open fun getAdminLogs(pageInfo: PageInfo, admin_id: Int): Page<Log> {
        val pageRequest = PageRequest(pageInfo.page - 1, pageInfo.size, Sort(Sort.Order(Sort.Direction.DESC, "id")))
        return logRepository.findAll({ root: Root<Log>, criteriaQuery: CriteriaQuery<*>, criteriaBuilder: CriteriaBuilder ->
            if (pageInfo.search.isBlank()) {
                val c1 = criteriaBuilder.equal(root.get<String>("type"), "admin")
                val c2 = criteriaBuilder.equal(root.get<Int>("admin_id"), admin_id)
                criteriaBuilder.and(c1, c2)
            } else {
                val search = getSearch(pageInfo.search, root, criteriaQuery, criteriaBuilder)

                val c1 = criteriaBuilder.equal(root.get<String>("type"), "admin")
                val c2 = criteriaBuilder.equal(root.get<Int>("admin_id"), admin_id)

                criteriaBuilder.and(c1, c2, search)
            }
        }, pageRequest)
    }


    open fun getAdminLogs(id: Int, admin: Admin): Log? {
        return logRepository.findByIdAndAdmin(id, admin)
    }

    open fun getUserLogs(pageInfo: PageInfo): Page<Log> {
        val pageRequest = PageRequest(pageInfo.page - 1, pageInfo.size, Sort(Sort.Order(Sort.Direction.DESC, "id")))
        return logRepository.findAll({ root: Root<Log>, criteriaQuery: CriteriaQuery<*>, criteriaBuilder: CriteriaBuilder ->
            if (pageInfo.search.isBlank()) {
                criteriaBuilder.equal(root.get<String>("type"), "user")
            } else {
                val search = getSearch(pageInfo.search, root, criteriaQuery, criteriaBuilder)

                val c1 = criteriaBuilder.equal(root.get<String>("type"), "user")

                criteriaBuilder.and(c1, search)
            }
        }, pageRequest)
    }

    open fun getUserLogs(pageInfo: PageInfo, user_id: Int): Page<Log> {
        val pageRequest = PageRequest(pageInfo.page - 1, pageInfo.size, Sort(Sort.Order(Sort.Direction.DESC, "id")))
        return logRepository.findAll({ root: Root<Log>, criteriaQuery: CriteriaQuery<*>, criteriaBuilder: CriteriaBuilder ->
            if (pageInfo.search.isBlank()) {
                val c1 = criteriaBuilder.equal(root.get<String>("type"), "user")
                val c2 = criteriaBuilder.equal(root.get<Int>("user_id"), user_id)
                criteriaBuilder.and(c1, c2)
            } else {
                val search = getSearch(pageInfo.search, root, criteriaQuery, criteriaBuilder)

                val c1 = criteriaBuilder.equal(root.get<String>("type"), "user")
                val c2 = criteriaBuilder.equal(root.get<Int>("user_id"), user_id)

                criteriaBuilder.and(c1, c2, search)
            }
        }, pageRequest)
    }

    open fun getUserLogs(id: Int, user: User): Log? {
        return logRepository.findByIdAndUser(id, user)
    }

    private fun getSearch(search: String, root: Root<Log>, criteriaQuery: CriteriaQuery<*>, criteriaBuilder: CriteriaBuilder): Predicate? {
        val c1 = criteriaBuilder.like(root.get("actionType"), "%$search%")
        val c2 = criteriaBuilder.like(root.get("actionText"), "%$search%")

        val c3 = criteriaBuilder.like(root.get("addIp"), "%$search%")
        val c4 = criteriaBuilder.like(root.get("addUa"), "%$search%")
        val c5 = criteriaBuilder.like(root.get("addTime"), "%$search%")
        return criteriaBuilder.or(c1, c2, c3, c4, c5)
    }

    init {
        logger.info("Initialized ${this.javaClass.simpleName}...")
    }

    @PostConstruct
    open fun post() {
        logger.info("PostConstruct ${this.javaClass.simpleName}...")
    }

    companion object {
        private val logger = LoggerFactory.getLogger(LogService::class.java)
    }
}